home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 September
/
CHIP Eylül 1998.iso
/
Slackwar
/
docs
/
mini
/
Serial-Port-Programming
< prev
next >
Wrap
Text File
|
1997-04-01
|
25KB
|
667 lines
Linux Serial Port Programming Mini-Howto
Antonino Iannella, antonino@usa.net
Version 1.0, March 9th 1997
1. Introduction
This document describes how to program the RS-232 ports for serial
communications, under PC-Linux. It covers information about
the serial ports, RS232 connections, modem issues, and the C programming
logic.
2. Background
For our final year project, our group had to design a concept World
Wide Web browser. Our prototype was a hand-held device which plugged
into a PC's COM2 (25-pin) serial port. The user would issue commands
to the browser (eg Back, Open, etc) by sending character commands to
the PC. The browser software would detect it, and perform the required
operation.
The method provided in the 'Linux I/O port programming mini-HOWTO'
did not act reliably. Often, an incorrect value would be received.
The information within provided a 100% reliable, quasi-POSIX-compliant
approach to communication.
The program provided at the end of this 0 formed the basis of
the PC's communication program. This document is written from the
1 needed for the web browser project. It revolves around
C programming for Linux, for a 9600 baud device attached to COM2.
3. Acknowledgements
The information here comes mainly from these sources -
Heavily based on the 'Serial Programming Guide for POSIX Compliant
Operating Systems', at http://www.easysw.com/~mike/serial/, by
mike@easysw.com. If you need greater detail or more information, then
this is the place to visit. Most of the information in this 0
originated here.
The 'Linux I/O port programming mini-HOWTO', by Riku Saikkonen
(rjs@spider.compart.fi). This document provides a different approach
to Linux serial programming.
'The Linux Serial HOWTO', by Greg Hankins, greg.hankins@cc.gatech.edu
describes how to set up serial communications devices on a Linux box.
It describes many aspects of serial devices and 0.
My two wonderful project partners: Gerel Enrile and Joyce Gong.
4. Copyright
This document is copyright (C) 1997 by Antonino Iannella.
It is covered under the general Linux HOWTO copyright agreement.
It is intended for the general public. it may be reproduced and
distributed in whole or in part, using any electronic or physical
medium. However, this copyright notice must remain on all copies.
Please forward question, suggestions, corrections, and all tidbits
of information to the author at antonino@usa.net
(or nettuno@light.iinet.net.au).
You will be acknowledged in future HOWTO revisions.
5. RS-232 connections
RS-232 is a standard for serial communications. It comes in different
varieties. The most common is RS-232C which defines a 'mark' bit as a
voltage between -3V and -12V, and a 'space' bit as a voltage between
+3V and +12V. RS-574 is the standard for 9-pin PC connectors and
voltages.
RS-232 basically consists of wires for serial communications; sending
and receiving, timing, status, and handshaking.
You can use a null modem cable as your connector.
The following pins are what were used for our project. We connected
the device to the DB-25 pin COM2 port. Please note that the Transmit
line from the PC must connect to the Receive line of the device, and
vice versa. Also, please note that a parallel port is different to a
serial port!
PC's pins Device's pins
TxD Transmit Data 2 - 3 RxD Receive Data
RxD Receive Data 3 - 2 TxD Transmit Data
SG Signal Ground 7 - 7 SG Signal Ground
Refer to the Linux Serial HOWTO for more specialised connections, and
detailed RS-232 pins.
6. Serial 0 and RS-232 definitions
The way that data get transmitted in serial communications is, well,
serially. One data bit is sent at a time. Each bit is either on (or the
'mark' state), or off (or the 'space' state).
The serial data throughput is usually expressed in bits-per-second (bps)
or baudot (baud). Throughput is the number of data bits (2 or off) that
may be sent in a second. Your modem might be able to support 115200 baud.
The project's web browser device was designed to run at 9600 baud.
RS-232 provides 18 different signals. About 6 are available to UNIX for
programming.
GND - Logic ground
Very important. Acts as a reference voltage, so the devices know
the relative voltage of the data transmitted.
TxD - Transmitted data
Carries the data transmitted from your PC.
A 'mark' voltage is interpreted as 1,
while a 'space' voltage is interpreted as 0.
RxD - Received data
Carries the data transmitted to your PC from the other device.
DCD - Data carrier detect
Is sent from the other device to your PC. A 'space' voltage means
that the device is still connected, or 'on-line'. This signal is
not always used or available.
DTR - Data terminal ready
Is sent from your PC to tell the device that you are ready (space)
or not-ready (mark). DTR is usually enabled automatically whenever
you access the serial interface.
CTS - Clear to send
Is sent from the other device to your PC.
A 'space' voltage means that your PC may send some data.
It is usually used to regulate the flow of serial data from your
PC, but it is not currently supported by all UNIX flavours.
RTS - Request to send
Is set to the 'space' voltage by your PC when it requests to send
more data. It also used to regulate data flow. Many systems leave
it on 'space' voltage all the time.
7. Communication issues
This section covers other issues of serial communication which might be
relevant to your particular application.
Since we are programming for asynchronous communication, we need the
PCs/devices to know where each character starts and ends in the serial
data flow.
In asynchronous mode, the serial data line stays in the mark state until
a character is sent. A 'start bit' is sent before each character; it is
always 0 and tells the PC/device that a character will follow.
After the start bit, the character's bits are sent, then a 'parity' bit,
and one or more stop bits.
The parity bit is a checksum of the data bits, indicating the number of
1 bits it contained -
Even parity - parity bit is 1 if there is an even number of 1s
Odd parity - parity bit is 1 if there is an odd number of 1s
Space parity - parity bit is always 0
Mark parity - parity bit is 1
No parity - no parity bit is sent or present.
'Stop' bits come at the end of every character. There may be 1, 1.5, or 2
stop bits. They used to be used to give the computer time to process the
character, but now they are used to synchronise the computer to the
incoming characters.
Asynchronous data is usually described like '8N1' - 8 data bits, no parity
bits, 1 stop bit. Another common one is '7N1'.
Flow control is used to regulate the data flow between devices, if there
is some sort of limitation, such as a slow device. There is 'Software
Flow Control' using special characters, XON and XOFF, to regulate the flow.
This method is not useful for transmitting non-textual data.
'Hardware Flow Control' uses the RTS and CTS signals instead of special
characters. The receiver sets CTS to space when it is ready to receive,
and to mark when it's not. The sender uses RTS the same way. This method
is faster than Software Flow Control, since it uses a separate set of
signals instead of extra bits.
Since the receive or transmit signal is at mark voltage until a new character
is sent. A 'break' condition exists when the line is set to low for 1/4
to 1/2 a second. It is used to reset a communications line, or change
the operation mode of devices like modems.
8. Basic port programming
Hopefully, all of the above is reasonably clear to you, so you may proceed
to program with confidence!
In UNIX all system devices are treated as (special) files. All serial ports
are opened, read from, written to, and closed, just like a binary file.
In Linux, the PC serial ports are
COM1 - /dev/ttyS0
COM2 - /dev/ttyS1
COM3 - /dev/ttyS2
COM4 - /dev/ttyS3
Firstly, open the serial port as a file. However, UNIX does not allow
devices to be accessed by normal users. To solve this, either run the
program as the superuser, or change the permission on the device as root,
eg
chmod a+rw /dev/ttyS1 (lets everyone access COM2)
To open the file do the following. Notice the three flags used in the
open() function. O_RDWR means that we open the port for reading and
writing. O_NOCTTY specifies that the program won't be the controlling
entity for the port. Most user programs don't want this feature.
O_NDELAY means that your program ignores the DCD line. If it didn't,
the program will be put to sleep until DCD is set to 'space' voltage.
/*
* 'open_port()' - Open serial port 1 - COM2.
*
* Returns the file descriptor on success or -1 on error.
*/
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{ /* Could not open the port */
fprintf(stderr, "open_port: Unable to open /dev/ttyS1 - %s\n",
strerror(errno));
}
return (fd);
}
If you need to write data to the port, do something like
n = write(fd, "ATZ\r", 4);
if (n < 0)
puts("write() of 4 bytes failed!\n");
Reading from the port is more complicated. If you open the port in 'raw
data' mode (the norm), each read() returns the number of characters actually
available in the serial buffers. However, if no characters are available,
read() will block until it receives characters, an interval timer expires,
or an error occurs. Use the following to make read return immediately.
FNDELAY makes read() return 0 if no characters were read.
fcntl(mainfd, F_SETFL, FNDELAY); /* Configure port reading */
To close the serial port, simply use
close(fd);
9. Port configuration
This section discusses how to configure the serial port for your device.
You will need to set the terminal attributes related to the port.
To do this, include <termios.h> and access the termios structure using the
POSIX tcgetattr() and tcsetattr() functions.
The termios structure contains
c_cflag - Control options
c_lflag - Line options
c_iflag - Input options
c_oflag - Output options
c_cc - Control characters
See section 12 for a list of c_cflag control modes.
They are used to set the baud rate, parity and stop bits, and flow control.
Always enable CLOCAL and CREAD, so the program does not own the port, and so
the serial interface driver will read incoming bytes.
9.1. Accessing the termios structure and the baud rate
Use cfsetospeed() and cfsetispeed() to set the baud rate.
CRTSCTS might be called CNEW_RTSCTS on other systems.
The following uses a termios structure called 'options'.
For our project, the device transmitted at 9600 baud and transmitted nothing
special.
tcgetattr(mainfd, &options); /* Get the current options for the port */
cfsetispeed(&options, B9600); /* Set the baud rates to 9600 */
cfsetospeed(&options, B9600);
/* Enable the receiver and set local mode */
options.c_cflag |= (CLOCAL | CREAD);
/* Set the new options for the port */
tcsetattr(mainfd, TCSANOW, &options);
The tcsetattr() function replaces the port's termios structure with the
settings you provided. The TCSANOW constant means that the changes should
occur immediately, without waiting for data transmission to complete.
Alternative choices are TCSADRAIN and TCSAFLUSH, which wait until buffers
are cleared. Refer to section 13.
9.2. Character size and parity
To set the character size, you must use bitwise logic.
The following code sets the character size to 8 data bits, and no parity.
options.c_cflag &= ~PARENB; /* Mask character size to 8 bits, no parity */
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; /* Select 8 data bits */
For other methods, refer to section 11.
9.3. Hardware flow control
To enable hardware flow control, use
options.c_cflag |= CRTSCTS; /* Enable hardware flow control */
To disable it,
options.c_cflag &= ~CRTSCTS; /* Disable hardware flow control */
9.4. Canonical and raw input
Canonical input means that all incoming characters are placed in a buffer
which may be edited by the user, until a carriage return or line feed (CR or
LF) are received. Typically, you would use
options.c_lflag |= ~(ICANON | ECHO | ECHOE);
Raw input is unprocessed, so they may be used as they are read.
Our device sent raw data.
options.c_lflag &= ~(ICANON | ECHO | ISIG);
Whether you use canonical or raw input, make sure you never enable input
echo when connected to a computer/device which is echoing characters to you.
Refer to section 14 for local mode constants.
9.5. POSIX input modes
Set the port's input modes for any input processing.
Set input parity when you have enabled parity in the c_cflag part.
Usually you'd use the following to enable parity checking, and strip the
parity bit off the data, before your program reads it.
options.c_iflag |= (INPCK | ISTRIP);
You might use IGNPAR, which ignores all parity errors. PARMRK marks parity
errors by inserting a DEL(255) and NUL character before the bad character.
If IGNPAR is enabled, only a NUL is inserted.
You may set software flow control using
options.c_iflag |= (IXON | IXOFF | IXANY);
Refer to section 15 for input mode constants.
9.6. POSIX output modes
To set port output modes, use the c_oflag member.
To select processed output, use the following. Of all the output modes, you
will probably only use ONCLR to convert newlines into CR and LFs.
options.c_oflag |= OPOST;
For raw output, use
options.c_oflag &= ~OPOST;
Refer to section 16 for output mode constants.
9.7. POSIX control modes
You may set the control characters using the c_cc part.
Set the software flow control characters in the VSTART and VSTOP
elements. The standard is DC1(17) and DC3(19) for XON and XOFF.
VMIN specifies the minimum number of 0 to read. If it is 0, then
VTIME specifies the time to wait for each character.
If VMIN is not 0, VTIME is the time to wait to read the first character.
If the first character is read, then any read() will be blocked until all
VMIN characters are read.
VTIME is specified in tenths of seconds. If it is 0, then read()s will
be permanently blocked unless NDELAY was previously specified with fcntl().
Refer to section 17 for control mode constants.
10. Sample program
This program is a skeleton COM2 reader, which was used for our project.
It did not need all of the information specified above for
configuring ports. The 20ms delay is used to indicate that data coming into
the port is buffered, and is available for the next read().
/* Better port reading program
v1.0
23-10-96
This test program uses quasi-POSIX compliant UNIX functions to
open the ABU port and read.
Uses termio functions to initialise the port to 9600 baud, at
8 data bits, no parity, no hardware flow control,
and features character buffering.
The 20ms delay after the port read indicates that characters are
buffered if a button is pressed many times.
This program was derived from instructions at
http://www.easysw.com/~mike/serial/
*/
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{ /* Could not open the port */
fprintf(stderr, "open_port: Unable to open /dev/ttyS1 - %s\n",
strerror(errno));
}
return (fd);
}
void main()
{
int mainfd=0; /* File descriptor */
char chout;
struct termios options;
mainfd = open_port();
fcntl(mainfd, F_SETFL, FNDELAY); /* Configure port reading */
/* Get the current options for the port */
tcgetattr(mainfd, &options);
cfsetispeed(&options, B9600); /* Set the baud rates to 9600 */
cfsetospeed(&options, B9600);
/* Enable the receiver and set local mode */
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB; /* Mask the character size to 8 bits, no parity */
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; /* Select 8 data bits */
options.c_cflag &= ~CRTSCTS; /* Disable hardware flow control */
/* Enable data to be processed as raw input */
options.c_lflag &= ~(ICANON | ECHO | ISIG);
/* Set the new options for the port */
tcsetattr(mainfd, TCSANOW, &options);
while (1)
{
read(mainfd, &chout, sizeof(chout)); /* Read character from ABU */
if (chout != 0)
printf("Got %c.\n", chout);
chout=0;
usleep(20000);
}
/* Close the serial port */
close(mainfd);
}
11. Character and parity settings
No parity (8N1):
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
Even parity (7E1):
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
Odd parity (7O1):
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
Mark parity is simulated by using 2 stop bits (7M1):
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
Space parity is setup the same as no parity (7S1):
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
12. POSIX control mode flags
The following table lists the possible control modes for c_cflag.
Constant Description
________________________
CBAUD Bit mask for baud rate
B0 0 baud (drop DTR)
B50 50 baud
B75 75 baud
B110 110 baud
B134 134.5 baud
B150 150 baud
B200 200 baud
B300 300 baud
B600 600 baud
B1200 1200 baud
B1800 1800 baud
B2400 2400 baud
B4800 4800 baud
B9600 9600 baud
B19200 19200 baud
B38400 38400 baud
EXTA External rate clock
EXTB External rate clock
CSIZE Bit mask for data bits
CS5 5 data bits
CS6 6 data bits
CS7 7 data bits
CS8 8 data bits
CSTOPB 2 stop bits (1 otherwise)
CREAD Enable receiver
PARENB Enable parity bit
PARODD Use odd parity instead of even
HUPCL Hangup (drop DTR) on last close
CLOCAL Local line - do not change 'owner' of port
LOBLK Block job control output
CRTSCTS Enable hardware flow control (not supported on all platforms)
13. POSIX tcsetattr Constants
Constant Description
______________________
TCSANOW Make changes now without waiting for data to complete
TCSADRAIN Wait until everything has been transmitted
TCSAFLUSH Flush input and output buffers and make the change
14. POSIX Local Mode Constants
Constant Description
______________________
ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
ICANON Enable canonical input (else raw)
XCASE Map uppercase \lowercase (obselete)
ECHO Enable echoing of input characters
ECHOE Echo erase character as BS-SP-BS
ECHOK Echo NL after kill character
ECHONL Echo NL
NOFLSH Disable flushing of input buffers after interrupt
or quit characters
IEXTEN Enable extended functions
ECHOCTL Echo control characters as ^char and delete as ~?
ECHOPRT Echo erased character as character erased
ECHOKE BS-SP-BS entire line on line kill
FLUSHO Output being flushed
PENDIN Retype pending input at next read or input char
TOSTOP Send SIGTTOU for background output
15. POSIX Input Mode Constants
Constant Description
______________________
INPCK Enable parity check
IGNPAR Ignore parity errors
PARMRK Mark parity errors
ISTRIP Strip parity bits
IXON Enable software flow control (outgoing)
IXOFF Enable software flow control (incoming)
IXANY Allow any character to start flow again
IGNBRK Ignore break condition
BRKINT Send a SIGINT when a break condition is detected
INLCR Map NL to CR
IGNCR Ignore CR
ICRNL Map CR to NL
IUCLC Map uppercase to lowercase
IMAXBEL Echo BEL on input line too long
16. POSIX Output Mode Constants
Constant Description
______________________
OPOST Postprocess output (not set = raw output)
OLCUC Map lowercase to uppercase
ONLCR Map NL to CR-NL
OCRNL Map CR to NL
NOCR No CR output at column 0
ONLRET NL performs CR function
OFILL Use fill characters for delay
OFDEL Fill character is DEL
NLDLY Mask for delay time needed between lines
NL0 No delay for NLs
NL1 Delay further output after newline for 100 milliseconds
CRDLY Mask for delay time needed to return carriage to left column
CR0 No delay for CRs
CR1 Delay after CRs depending on current column position
CR2 Delay 100 milliseconds after sending CRs
CR3 Delay 150 milliseconds after sending CRs
TABDLY Mask for delay time needed after TABs
TAB0 No delay for TABs
TAB1 Delay after TABs depending on current column position
TAB2 Delay 100 milliseconds after sending TABs
TAB3 Expand TAB characters to spaces
BSDLY Mask for delay time needed after BSs
BS0 No delay for BSs
BS1 Delay 50 milliseconds after sending BSs
VTDLY Mask for delay time needed after VTs
VT0 No delay for VTs
VT1 Delay 2 seconds after sending VTs
FFDLY Mask for delay time needed after FFs
FF0 No delay for FFs
FF1 Delay 2 seconds after sending FFs
17. POSIX Control Character Constants
Constant Description Key
______________________________________
VINTR Interrupt CTRL-C
VQUIT Quit CTRL-Z
VERASE Erase Backspace (BS)
VKILL Kill-line CTRL-U
VEOF End-of-file CTRL-D
VEOL End-of-line Carriage return (CR)
VEOL2 Second end-of-line Line feed (LF)
VMIN Minimum number of characters to read
VTIME Time to wait for data (tenths of seconds)
----------------- End of Linux Serial Programming Mini-Howto -----------------